/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package treeship.core.service;

import java.util.List;

import treeship.core.archetype.impl.ArchetypeFamilyImpl;
import treeship.core.archetype.impl.ArchetypePropertyImpl;
import treeship.core.archetype.impl.ArchetypeShipImpl;
import treeship.core.archetype.impl.DimensionContextImpl;
import treeship.core.archetype.impl.PropertyContextImpl;
import treeship.core.service.impl.ArchetypesRepositoryImpl;
import treeship.core.service.impl.ContextDataImpl;
import treeship.core.service.xml.DocumentWrapper;
import treeship.core.service.xml.NodeWrapper;

/**
 * 
 * @author moonchild
 */
public class ConfigurationParser {

	private ArchetypesRepositoryImpl repository;

	public ConfigurationParser(ArchetypesRepositoryImpl repository) {
		this.repository = repository;
	}

	public void parseProcess(DocumentWrapper docWrap) {
		processContextList(docWrap);
		processPropertyList(docWrap);
		processFamilyList(docWrap);
		processEntityList(docWrap);
	}

	private void processEntityList(DocumentWrapper doc) {
		final List<NodeWrapper> listaEntita = doc
				.getListChildrenOfStaticTag(Constants.ENTITYLIST);
		for (NodeWrapper item : listaEntita) {
			processEntityDefinition(item);
		}
		for (NodeWrapper item : listaEntita) {
			processEntityHierarchy(item);
		}

	}

	private void processEntityHierarchy(NodeWrapper item) {
		NodeWrapper nomeWrap = item.getChild(Constants.NAME);
		NodeWrapper compsWrap = item.getChild(Constants.CHILDREN);
		NodeWrapper creativesWrap = item.getChild(Constants.CREATIVES);
		if (nomeWrap != null) {
			ArchetypeShipImpl currentShip = repository
					.getArchetypeShipFor(nomeWrap.getValue());
			if (compsWrap != null) {
				for (NodeWrapper comp : compsWrap.getChildren()) {
					String nomeComp = comp.getAttribute(Constants.NAME);
					Double weight = comp.getAttributeAsDoubleWithDefault(
							Constants.WEIGHT, 1.0);
					ArchetypeShipImpl componente = repository
							.getArchetypeShipFor(nomeComp);
					if (componente != null) {
						currentShip.addComponent(componente, weight);
					} else {
						Nexus.getLogger()
								.addLog(nomeComp
										+ " isn't a recognized child, check the spelling");
					}
				}
			}

			if (creativesWrap != null) {
				for (NodeWrapper creative : creativesWrap.getChildren()) {
					String nomeCreative = creative.getAttribute(Constants.NAME);
					final ArchetypeShipImpl shipCreative = repository
							.getArchetypeShipFor(nomeCreative);
					if (shipCreative != null) {
						currentShip.addCreative(shipCreative);
					} else {
						Nexus.getLogger()
								.addLog(nomeCreative
										+ " isn't a recognized creative, check the spelling");
					}
				}
			}

		}

	}

	private void processEntityDefinition(NodeWrapper entityNode) {
		ArchetypeShipImpl tempShip = new ArchetypeShipImpl();
		// this boolean is for when the tag <NAME> comes after <ID>
		boolean hasId = false;
		for (NodeWrapper nod : entityNode.getChildren()) {
			if (nod.getName().equals(Constants.NAME)) {
				tempShip.setName(nod.getValue());
				if (!hasId) {
					tempShip.setId(tempShip.getName().hashCode());
				}
			}

			if (nod.getName().equals(Constants.ID)) {
				tempShip.setId(nod.getValueAsLong());
				hasId = true;
			}

			if (nod.getName().equals(Constants.FAMILY)) {
				if (nod.getValue() != null && !nod.getValue().equals("")) {
					ArchetypeFamilyImpl fam = repository
							.getArchetypeFamilyFor(nod.getValue());
					tempShip.setFamily(fam);
				}
			}

			if (nod.getName().equals(Constants.OPEN)) {
				if (nod.getValue().equals(Constants.TRUE)) {
					tempShip.setOpen(true);
				} else if (nod.getValue().equals(Constants.FALSE)) {
					tempShip.setOpen(false);
				}
			}

			if (nod.getName().equals(Constants.SOLID)) {
				if (nod.getValue().equals(Constants.TRUE)) {
					tempShip.setSolid(true);
				} else if (nod.getValue().equals(Constants.FALSE)) {
					tempShip.setSolid(false);
				}
			}

			if (nod.getName().equals(Constants.DIMENSION)) {
				DimensionContextImpl dci = tempShip.getDimensionContext();
				dci.setDimensionAverage(nod.getValueAsDouble());
				dci.setDimensionVariant(nod.getAttributeAsDoubleWithDefault(
						Constants.VARIANCE, 0.0));
			}

			if (nod.getName().equals(Constants.FREESPACE)) {
				DimensionContextImpl dci = tempShip.getDimensionContext();
				dci.setFreeSpaceAverage(nod.getValueAsDouble());
				dci.setFreeSpaceVariant(nod.getAttributeAsDoubleWithDefault(
						Constants.VARIANCE, 0.0));
			}

			if (nod.getName().equals(Constants.SPEED)) {
				DimensionContextImpl dci = tempShip.getDimensionContext();
				dci.setSpeedAverage(nod.getValueAsDouble());
				dci.setSpeedVariant(nod.getAttributeAsDoubleWithDefault(
						Constants.VARIANCE, 0.0));
			}

			if (nod.getName().equals(Constants.PROPERTIES)) {
				for (NodeWrapper propertia : nod.getChildren()) {
					ArchetypePropertyImpl archetypeProperty = repository
							.getArchetypePropertyFor(propertia
									.getAttribute(Constants.NAME));
					Double deflt = propertia.getAttributeAsDoubleWithDefault(
							Constants.DEFAULT, 0.0);
					Double variant = propertia.getAttributeAsDoubleWithDefault(
							Constants.VARIANCE, 0.0);
					Double min = propertia.getAttributeAsDoubleWithDefault(
							Constants.MIN, 0.0);
					PropertyContextImpl pci = new PropertyContextImpl();
					pci.setProperty(archetypeProperty);
					pci.setAverage(deflt);
					pci.setVariant(variant);
					pci.setMin(min);
					tempShip.addProperty(pci);
				}
			}
			// if (nod.getName().equals(Constants.ACTIONS)) {
			// for (NodeWrapper act : nod.getChildren()) {
			// ArchetypeActionImpl archAction =
			// repository.getArchetypeActionFor(act.getAttribute(Constants.NAME));
			// tempShip.addAction(archAction);
			// }
			// }
		}

		repository.addArchetypeShip(tempShip);
	}

	private void processPropertyList(DocumentWrapper doc) {
		for (NodeWrapper item : doc
				.getListChildrenOfStaticTag(Constants.PROPERTYLIST)) {
			processPropertyDefinition(item);
		}
		for (NodeWrapper item : doc
				.getListChildrenOfStaticTag(Constants.PROPERTYLIST)) {
			processPropertyFocus(item);
		}
	}

	private void processFamilyList(DocumentWrapper doc) {
		for (NodeWrapper item : doc
				.getListChildrenOfStaticTag(Constants.FAMILYLIST)) {
			processFamilyDefinition(item);
		}
	}

	private void processContextList(DocumentWrapper doc) {
		ContextDataImpl contextData = repository.getContextData();
		for (NodeWrapper item : doc
				.getListChildrenOfStaticTag(Constants.GLOBALIDS)) {
			if (item.getName().equals(Constants.IDDIMENSION)) {
				contextData.setIdDimension(item.getValueAsLong());
			} else if (item.getName().equals(Constants.IDFREESPACE)) {
				contextData.setIdFreespace(item.getValueAsLong());
			} else if (item.getName().equals(Constants.IDPOSITION)) {
				contextData.setIdPosition(item.getValueAsLong());
			} else if (item.getName().equals(Constants.IDSPEED)) {
				contextData.setIdSpeed(item.getValueAsLong());
			} else if (item.getName().equals(Constants.SOLIDITYENABLED)) {
				contextData.setSolidityEnabled(item.getValueAsBoolean());
			}
		}
	}

	private void processPropertyDefinition(NodeWrapper item) {
		String nome = item.getAttribute(Constants.NAME);
		// long id = nome.hashCode();

		ArchetypePropertyImpl newArchProperty = new ArchetypePropertyImpl(nome);
		if (item.hasAttribute(Constants.ID)) {
			long id = item.getAttributeAsLong(Constants.ID);
			newArchProperty.setId(id);
		}
		repository.addArchetypeProperty(newArchProperty);
	}

	private void processFamilyDefinition(NodeWrapper item) {
		String nome = item.getAttribute(Constants.NAME);
		// long id = nome.hashCode();

		ArchetypeFamilyImpl newFamily = new ArchetypeFamilyImpl();
		newFamily.setName(nome);
		repository.addArchetypeFamily(newFamily);
	}

	private void processPropertyFocus(NodeWrapper item) {
		if (item.hasAttribute(Constants.FOCUS)) {
			String nome = item.getAttribute(Constants.NAME);
			String nomeFocus = item.getAttribute(Constants.FOCUS);

			ArchetypePropertyImpl thisProperty = repository
					.getArchetypePropertyFor(nome);
			ArchetypePropertyImpl focus = repository
					.getArchetypePropertyFor(nomeFocus);
			thisProperty.setFocus(focus);
		}
	}
}
